package com.wsjzzcbq.wsjzcode.compile.java;

import com.wsjzzcbq.wsjzcode.compile.JavaCodeCompiler;
import com.wsjzzcbq.wsjzcode.consts.LangTypeEnum;
import com.wsjzzcbq.wsjzcode.util.FileUtils;
import com.wsjzzcbq.wsjzcode.util.JavaCodeUitls;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * JavaCompiler
 * 文件编译java
 *
 * @author wsjz
 * @date 2023/07/06
 */
@Slf4j
@Component
public class JavaCodeFileCompiler implements JavaCodeCompiler {

    @Value("${basePath}")
    private String basePath;

    private void create(String code) throws IOException {
        //先判断临时文件目类是否存在
        if (!Files.exists(Paths.get(basePath))) {
            //不存在则创建
            Files.createDirectory(Paths.get(basePath));
        }
        //创建前先清空文件目录
        FileUtils.deleteDirectory(basePath);
        String className = JavaCodeUitls.getClassName(code);
        createJavaFromSource(className, code);
    }

    private void createJavaFromSource(String className, String source) throws IOException {
        String filePath = basePath + className + LangTypeEnum.Java.getValue();
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
        Files.write(file.toPath(), Arrays.asList(source.split("\n")), StandardCharsets.UTF_8);
    }

    @Override
    public Map<String, Object> compile(String code) {
        //创建java文件
        try {
            create(code);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        String className = JavaCodeUitls.getClassName(code);

        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        String fileName = basePath + className + LangTypeEnum.Java.getValue();

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int result = javac.run(null, null, byteArrayOutputStream, "-d", basePath, fileName);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        try {
            byteArrayOutputStream.flush();
            byteArrayOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Map<String, Object> map = new HashMap<>(2);
        //返回0编译成功，非0失败
        if (result == 0) {
            map.put("result", true);
            return map;
        }

        String content = new String(bytes, StandardCharsets.UTF_8);
        map.put("result", false);
        map.put("error", content.substring(basePath.length()));
        return map;
    }

    @Override
    public Object run(String className, String methodName) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        URL[] urls = new URL[0];
        try {
            urls = new URL[]{new URL("file:" + basePath)};
        } catch (MalformedURLException e) {
            log.error(e.getMessage(), e);
        }
        URLClassLoader urlClassLoader = new URLClassLoader(urls);

        Class cls = urlClassLoader.loadClass(className);

        Method executeMethod = cls.getMethod(methodName);
        Object obj = cls.getConstructor().newInstance();
        Object ret = executeMethod.invoke(obj);
        return ret;
    }
}
